/**
	License:		Artistic license 2.0 (see license.txt, also available online at http://www.perlfoundation.org/artistic_license_2_0)
	Authors:		OrbitalLab (http://www.orbitallab.ru/moonglide/), 2007-2009

	File:			OpenGLWin32.d
	Description:	all Windows(os)-dependent stuff for OpenGL
	Date:			11.04.2008 by Digited
*/
module moonglide.renderer.opengl.platform.OpenGLWin32;

version( Windows )
{

import
	tango.sys.win32.UserGdi,
	tango.sys.win32.Macros,

	derelict.opengl.wgl,
	derelict.opengl.extension.ext.wglswapcontrol,

	moonglide.util.MoonUtil,

	moonglide.renderer.opengl.GL,
	moonglide.renderer.IRendererOS,

	moonglide.os.win32.Win32OS;

//===============================================================
/// OpenGLWin32 - class with OS specified code for opengl renderer
//===============================================================
class COpenGLWin32 : IRendererOS
{
	protected:
		CWin32OS	_ios;
		bool		_initialized,
					_deinitialized;

		HWND		_hWnd;
		HANDLE 		_hDC = null,
					_hRC = null;

		GLuint		_font_id_base;
		GLYPHMETRICSFLOAT gmf[256];

		void _initFont()
		{
			_font_id_base = glGenLists(256);

			HFONT  font = CreateFontA( -12, 0, 0, 0, FW_NORMAL, false, false, false, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
				PROOF_QUALITY, FF_DONTCARE|DEFAULT_PITCH, "Comic Sans MS" );

			SelectObject( _hDC, font );
			//wglUseFontOutlines( _hDC, 0, 256, _font_id_base, 0.0F, 0.2F, WGL_FONT_POLYGONS,
				//cast(derelict.util.wintypes.GLYPHMETRICSFLOAT*)gmf.ptr );
			wglUseFontBitmaps(_hDC, 0, 256, _font_id_base);
		}

		void _deInitFont()
		{
			glDeleteLists( _font_id_base, 256 );
		}

	public:
		//===============================================================
		/// Initialize - init stuff, os dependent (win32). Look at parameters and guess what does it do.
		//===============================================================
		bool initialize(
			char[]			windowName,
			inout Size2ui	windowSize,
			ubyte			bpp,
			ubyte			refreshFreq,
			bool			fullscreen,
			bool 			vsync,
			bool 			antialiasing,
			bool 			stencil )
		{
			if( !_ios.createPlatformWindow( windowSize, fullscreen, windowName ) )
			{
				errorLog( "Renderer: ios returned error on creating a window" );
				return false;
			}

			if( fullscreen )
			{
				if( !_ios.changeScreenResolution( windowSize.x, windowSize.y, bpp, fullscreen, refreshFreq ) )
				{
					errorLog( "Renderer: ios returned error on changing screen resolution" );
					return false;
				}
			}

			PIXELFORMATDESCRIPTOR pfd;

			with( pfd )
			{
				nSize				= 0;
				nVersion			= 1;

				dwFlags				= PFD_DRAW_TO_WINDOW |		// Format Must Support Window
										PFD_SUPPORT_OPENGL |	// Format Must Support OpenGL
										PFD_DOUBLEBUFFER;
				iPixelType			= PFD_TYPE_RGBA;

				cColorBits = bpp;	cRedBits = 0;
				cRedShift =0;		cGreenBits = 0;
				cGreenShift= 0;		cBlueBits= 0;
				cBlueShift=0;		cAlphaBits=0;
				cAlphaShift=0;		cAccumBits=0;
				cAccumRedBits=0;	cAccumGreenBits=0;
				cAccumBlueBits=0;	cAccumAlphaBits=0;
				cDepthBits=24;		cStencilBits=0;
				cAuxBuffers=0;		iLayerType=PFD_MAIN_PLANE;
				bReserved=0;		dwLayerMask=0;
				dwVisibleMask=0;	dwDamageMask=0;
			}

			_hWnd	= cast(HANDLE)_ios.getHandle();
			_hDC 	= GetDC( _hWnd );

			if( !_hDC )
			{
				errorLog( "Renderer: unable to get hDC from hwnd" );
				return false;
			}

			int PixelFormat = ChoosePixelFormat( _hDC, &pfd );

			if( !PixelFormat )
			{
				errorLog( "Renderer: unable to chose pixel format" );
				return false;
			}

			if( !SetPixelFormat( _hDC, PixelFormat, &pfd ) )
			{
				errorLog( "Renderer: unable to set pixel format" );
				return false;
			}

			_hRC = wglCreateContext( cast(derelict.util.wintypes.HDC)_hDC );

			// create rendering context
			if( !( _hRC  ) )
			{
				errorLog( "Renderer: unable to create context" );
				return false;
			}

			// activate rendering context
			if( !wglMakeCurrent( cast(derelict.util.wintypes.HDC)_hDC, cast(derelict.util.wintypes.HANDLE)_hRC ) )
			{
				errorLog( "Renderer: unable to make current rc" );
				return false;
			}

			DerelictGL.loadExtensions();

			if( !vsync )
			{
				traceLog.trace( "not vsync" );

				if( EXTwglswapcontrol.isEnabled )
				{
					wglSwapIntervalEXT( 0 );
					traceLog.trace( "vsync off!" );
				}
			}

			_initFont();

			_initialized = true;
			_deinitialized = false;

			traceLog.trace( "Platform OpenGL initialization done." );

			return true;
		}

		//===============================================================
		/// deInitialize - release & destroy os-dependent stuff
		//===============================================================
		bool deInitialize()
		{
			if( !_initialized || _deinitialized )
				return false;

			_deinitialized = true;

			_deInitFont();

			debug debugLog.trace( "Starting  win32 opengl renderer shutdown..." );

			if( !_hRC )
			{
				wglMakeCurrent( null, null );
				wglDeleteContext( cast(derelict.util.wintypes.HANDLE)_hRC );
				_hRC = null;
			}

			if( !_hDC )
			{
				ReleaseDC( _hWnd, _hDC );
				_hDC = null;
			}

			return true;
		}

		//===============================================================
		/// Present frame - swap buffers, end of rendering. Must be called last while processing scene.
		//===============================================================
		bool presentFrame()
		{
			SwapBuffers( _hDC );
			return true;
		}


		this( IOS ios )
		{
			_ios = cast(CWin32OS)ios;
			moonAssert( _ios !is null, "casting ios to CWin32OS failed!", __FILE__, __LINE__ );
		}

        this()
		{
			deInitialize();
		}

		void printPlatformText( char[] line, Vector2f position, Color4f color )
		{
			float length;

			foreach( loop, letter; line )
				length += gmf[letter].gmfCellIncX;

			glDisable(GL_TEXTURE_2D);
			glDisable(GL_LIGHTING);

			glPushAttrib( GL_LIST_BIT );
			glListBase( _font_id_base );

			glColor4fv( color.ptr );
			glRasterPos2f(position.x, position.y);

			glCallLists( line.length, GL_UNSIGNED_BYTE, line.ptr );

			glPopAttrib();

			glEnable(GL_TEXTURE_2D);
			glEnable(GL_LIGHTING);

		}
} // end class COpenGLWin32

} // end version( Windows )
